#!/usr/bin/lua
require("lua-xwrt.addon.string")
require("lua-xwrt.addon.uci")
local util = require("lua-xwrt.xwrt.util")
local general = { 
	"context",
	"allowguest",
	"allowoverlap",
	"allowtransfer",
	"realm",
	"bindport",
	"bindaddr",
	"srvlookup",
	"pedantic",
	"tos_sip",
	"tos_audio",
	"tos_video",
	"maxexpiry",
	"minexpiry",
	"defaultexpiry",
	"t1min",
	"notifymimetype",
	"checkmwi",
	"buggymwi",
	"vmexten",
	"disallow",
	"allow",
	"mohinterpret",
	"mohsuggest",
	"language",
	"relaxdtmf",
	"trustrpid",
	"sendrpid",
	"progressinband",
	"useragent",
	"promiscredir",
	"usereqphone",
	"dtmfmode",
	"compactheaders",
	"videosupport",
	"maxcallbitrate",
	"callevents",
	"alwaysauthreject",
	"g726nonstandard",
	"matchexterniplocally",
	"dynamic_exclude_static",
	"contactdeny",
	"contactpermit",
	"regcontext",
	"rtptimeout",
	"rtpholdtimeout",
	"rtpkeepalive",
	"sipdebug",
	"recordhistory",
	"dumphistory",
	"allowsubscribe",
	"subscribecontext",
	"notifyringing",
	"notifyhold",
	"limitonpeers",
	"t38pt_udptl",
	"register",
	"registertimeout",
	"registerattempts",
	"externip",
	"externhost",
	"externrefresh",
	"localnet",
	"nat",
	"canreinvite",
	"directrtpsetup",
	"canreinvite",
	"canreinvite",
	"rtcachefriends",
	"rtsavesysname",
	"rtupdate",
	"rtautoclear",
	"ignoreregexpire",
	"domain",
	"allowexternaldomains",
	"autodomain",
	"fromdomain",
	"jbenable",
	"jbforce",
	"jbmaxsize",
	"jbresyncthreshold",
	"jbimpl",
	"jblog"
	}
	
local user = {
		"type",
		"context",
		"callingpres",
		"deny",
		"permit",
		"secret",
		"username",
		"defaultuser",
		"authuser",
		"md5secret",
		"dtmfmode",
		"canreinvite",
		"nat",
		"callgroup",
		"pickupgroup",
		"language",
		"disallow",
		"allow",
		"insecure",
		"trustrpid",
		"progressinband",
		"promiscredir",
		"useclientcode",
		"accountcode",
		"setvar",
		"callerid",
		"amaflags",
		"call-limit",
		"allowoverlap",
		"allowsubscribe",
		"allowtransfer",
		"subscribecontext",
		"videosupport",
		"maxcallbitrate",

		"rfc2833compensate",
		"t38pt_usertpsource"
}

local peer = {	
		"type",
		"context",
		"callingpres",
		"deny",
		"permit",
		"secret",
		"md5secret",
		"dtmfmode",
		"canreinvite",
		"nat",
		"callgroup",
		"pickupgroup",
		"language",
		"disallow",
		"allow",
		"insecure",
		"trustrpid",
		"progressinband",
		"promiscredir",
		"useclientcode",
		"accountcode",
		"setvar",
		"callerid",
		"amaflags",
		"call-limit",
		"allowoverlap",
		"allowsubscribe",
		"allowtransfer",
		"subscribecontext",
		"videosupport",
		"maxcallbitrate",

		"mailbox",
--		"username",
		"defaultuser",
		"authuser",
--		"template",
		"fromdomain",
		"regexten",
		"fromuser",
		"host",
		"port",
		"qualify",
		"defaultip",
		"rtptimeout",
		"rtpholdtimeout",
		"sendrpid",
		"outboundproxy",

		"rfc2833compensate",
		"t38pt_usertpsource",

		"contactpermit",
		"contactdeny"
}

local astFile = "asterisk"

function start_file(label)
	local gen = "Generated by LuaIPBX"
	local len, res = util.intdiv(string.len(gen),2)

	local str = ";"..string.rep("*",78).."\n"
	str = str..";"..string.rep("*",3)..string.rep(" ",36-len)
	str = str..gen..string.rep(" ",36-len+res).."***\n"

	len, res = util.intdiv(string.len(label),2)
	str = str..";"..string.rep("*",3)..string.rep(" ",36-len)
	str = str..label..string.rep(" ",36-len-res).."***\n"
	str = str..";"..string.rep("*",78).."\n"
	return str
end

function mysort(t)
	table.sort(t, function (a,b)
	return (a[".index"] < b[".index"])
	end)
end

function dialprio(ord,prov)
	for i, line in pairs(prov.dial) do
		for par in string.gmatch(line,"%S+") do
			local _, _, dial, prio, prefix = string.find(par,"([A-Za-z0-9_]+)%s*[%=%:]*%s*([0-9]+)%s*[%:]*%s*([0-9]*)")
			prio = tonumber(prio)
			prefix = prefix or ""
			if ord[dial] == nil then ord[dial] = {} end
			if prio > 0 then
				while ord[dial][prio] ~= nil do
					prio = prio + 1
				end
				ord[dial][prio]={}
				ord[dial][prio]["device"] = prov.name
				ord[dial][prio]["protocol"] = prov.protocol
				ord[dial][prio]["prefix"] = prefix
			end
		end
	end
end

function phones()
	local str = "[phones]\n"
	for n, t in pairs(uci.get_type(astFile,"phone")) do
		if t.dial and t.dial ~= "" then
			local sep = ""
			local diallist = ""
			for i, d in ipairs(t.dial) do
				if d ~= "" then
					for device in string.gmatch(d,"%S+") do
						diallist = diallist .. sep ..(uci.get(astFile,device,"protocol") or "SIP").."/"..device
						sep = "&"
					end
				end
			end
			str = str.."exten => "..t[".name"]..",1,Dial("..diallist..")\n"
		end
	end
	return str
end

function getDials(dials)
	local str = ""
	if dials then
		for d,t in pairs(dials) do
			for k,v in ipairs(t) do
				str = str..v.."\n"
			end
			str = str.."\n"
		end
	end
	return str
end

function getPatterns(trunks)
	local str = ""
	if trunks then
		for d,t in pairs(trunks) do
			for k,v in ipairs(t) do
				str = str .. v .. "\n"
			end
			str = str .. "\n"
		end
	end
	return str
end

function getContexts(contexts)
	local str = ""
	if contexts then
		for k,t in ipairs(contexts) do
			str = str ..setVars(t[".name"],t.include,"include => ")
--			str = str .. "\n"
		end
	end
	return str
end

function getIAXprovider()
	return [[
[iaxprovider]
;switch => IAX2/user:[key]@myserver/mycontext
;switch => IAX2/siupIPBX:nevera01@172.17.0.56/from_child
switch => IAX2/testsiup:testing@204.117.121.235/full_phones

]]
end

function orderByTable(input, order)
	local ret = {}
	for _, v in ipairs(order) do
		if input[v] then
			ret[#ret+1] = {}
			ret[#ret]["name"] = v
			ret[#ret]["value"] = input[v]
		end
	end
	return ret
end

function getTemplates(templates)
	local tmp = cleanUciList(templates)
	local str = ""
	local sep = ""
	if tmp then
		for i,l in ipairs(tmp) do
				str = str .. sep .. l
				sep = ", "
		end
	end
	if str ~= "" then
		str = "("..str..")"
	end
	return str
end

function textContext(input,order)
	local ctx = orderByTable(input, order)
	local str = ""
	for _, t in pairs(ctx) do
		if type(t.value) == "table" then
			tlist = cleanUciList(t.value)
			for _, line in ipairs(tlist) do
				str = str .. t.name .. "=" .. line .. "\n"
			end
		else
			str = str .. t.name .. "=" .. t.value .. "\n"
		end
	end
	return str
end

function makeTemplates()
	local tmp = uci.get_type(astFile,"template")
	local str = ""
	if tmp then
		for i, ctx in ipairs(tmp) do
			str = str .. "["..ctx.name.."](!)\n"
			str = str .. textContext(ctx,peer)
			str = str .. "\n"
		end
	end
	return str
end

function makeSipConf(tsip,providers)
	local str = start_file("sip.conf")
	str = str..setVars("general",uci.get(astFile,"sip","general"))
	str = str..setVars("authentication",uci.get(astFile,"sip","authentication"))
	str = str..makeTemplates()
	if tsip then
		for i, ctx in pairs(tsip) do
			str = str .. "["..ctx.name.."]"..getTemplates(ctx.template).."\n"
			str = str .. textContext(ctx,peer)
			str = str .. "\n"
		end
	end
	if providers then
		for i, ctx in pairs(providers) do
			if ctx.protocol == "SIP" then
				str = str .. "["..ctx.name.."]".."\n"
				str = str .. textContext(ctx,peer)
				str = str .. "\n"
			end
		end
	end
	return str
end

function makeIaxConf(tsip,providers)
	local str = start_file("iax.con")
	str = str..setVars("general",uci.get(astFile,"iax","general"))
	str = str..makeTemplates()
	if tsip then
		for i, ctx in pairs(tsip) do
			str = str .. "["..ctx["name"].."]"..getTemplates(ctx.template).."\n"
			str = str .. textContext(ctx,peer)
			str = str .. "\n"
		end
	end
	if providers then
		for i, ctx in pairs(providers) do
			if ctx.protocol == "IAX2" then
				str = str .. "["..ctx.name.."]".."\n"
				str = str .. textContext(ctx,peer)
				str = str .. "\n"
			end
		end
	end
	return str
end

function makeExtensionsConf(dials,trunks,contexts)
	local extensions_conf = start_file("extensions.conf")
	extensions_conf = extensions_conf..setVars("general",uci.get(astFile,"extensions","general"))
	extensions_conf = extensions_conf..setVars("globals",uci.get(astFile,"extensions","globals"))
	extensions_conf = extensions_conf..getIAXprovider()
	extensions_conf = extensions_conf..getDials(dials)
	extensions_conf = extensions_conf..getPatterns(trunks)
	extensions_conf = extensions_conf..getContexts(contexts)
	extensions_conf = extensions_conf..phones()
	return extensions_conf
end

function setVars(section, tvalues, prefix)
	local str = ""
	if tvalues then
		if section then
			str = str.."["..section.."]\n"
		end
		for i, v in ipairs(cleanUciList(tvalues)) do
			if prefix then
				str = str .. prefix .. v .. "\n"
			else
				str = str .. v .. "\n"
			end
		end
		str = str .. "\n"
	end
	return str
end

function cleanUciList(tlist)
	retlist = {}
	if tlist then
	for k, v in ipairs(tlist) do
		v = string.gsub(v,"(%S+)%s*([=>+]+)%s*(%S+)","%1%2%3")
		for line in string.gmatch(v,"%S+") do
--			line = string.gsub(line,"(%S+)%s*([=>+]+)%s*(%S+)","%1 %2 %3")
			retlist[#retlist+1]=line
		end
	end
	end
	return retlist
end

function makeManager()
	local ast = uci.get_all("asterisk")
	local str = start_file("manager.conf")
	str = str .. setVars("general",uci.get(astFile,"manager","general"))
	for k, v in pairs(ast.manager) do
		if type(v) == "table" and k ~= "general" then
			str = str..setVars(k,uci.get(astFile,"manager",k))
		end
	end
	return str
end

function makeFeatures()
	local str = start_file("features.conf")
	str = str .. setVars("general",uci.get(astFile,"features","general"))
	str = str .. setVars("features",uci.get(astFile,"features","features"))
	str = str .. setVars("applicationmap",uci.get(astFile,"features","applicationmap"))
	return str
end

function makeHttp()
	local str = start_file("http.conf")
	str = str .. setVars("general",uci.get(astFile,"http","general"))
	str = str .. setVars("post_mappings",uci.get(astFile,"http","post_mappings"))
	return str
end

function makeMusicOnHold()
	local ast = uci.get_all(astFile)
	local str = start_file("musiconhold.conf")
	for k,v in pairs(ast.musiconhold) do
		if type(v) == "table" then
			str = str .. setVars(k,v)
		end
	end
--	str = str .. "\n"
	return str
end

local calls = uci.get_type(astFile,"call")
local providers = uci.get_type(astFile,"provider")
local gral_extensions = uci.get(astFile,"extensions","general")
local contexts = uci.get_type(astFile,"context")

local dials = {}
local trunks = {}
local provord = {}
if providers then
	for i, t in pairs(providers) do
		dialprio(provord,t)
	end
end

for i,t in pairs(calls) do
	local name = t.name
	local prefix = t.prefix or ""
	local pattern = t.pattern or "."
	local len = string.len(prefix)
	local init = "exten => _"..prefix..pattern
	local dinit = "exten => _"..pattern
	trunks[name] = {}
	dials[name] = {}
	table.insert(trunks[name], "["..name.."_dest]")
	table.insert(trunks[name], init..",1,NoOp(Destination: "..name..")")
	table.insert(trunks[name], init..",n,Set(ToDial=${EXTEN:"..len.."})")
	table.insert(trunks[name], init..",n,Goto("..name.."_dial,${ToDial},1)")
	table.insert(dials[name], "["..name.."_dial]")
	table.insert(dials[name], dinit..",1,NoOp("..name.."_dial)")
	if provord[name] then
		for i, prov in pairs(provord[name]) do
			local protocol = prov.protocol or ""
			local device = prov.device or ""
			local prefix = prov.prefix or ""
			if protocol ~= "" then protocol = protocol.."/" end
			if device ~= "" then device = device.."/" end
			table.insert(dials[name], dinit..",n,Dial("..protocol..device..prefix.."${EXTEN})")
			table.insert(dials[name], dinit..[[,n,NoOp(DialStatus: ${DIALSTATUS})]])
			table.insert(dials[name], dinit..[[,n,GotoIf($["${DIALSTATUS}" = "ANSWER"]?fin,s,1)]])
		end
	end
end

local iaxDevices = {}
local sipDevices = {}
local unknowDevices = {}
for i, t in pairs(uci.get_type(astFile,"device")) do
	if t.protocol == "IAX2" then
		iaxDevices[#iaxDevices+1] = t
	elseif t.protocol == "SIP" then
		sipDevices[#sipDevices+1] = t
	else 
		unknowDevices[#unknowDevices+1] = t
	end
end

if arg[1]=="w" then
	local file = io.open("/etc/asterisk/extensions.conf","w")
	file:write(makeExtensionsConf(dials,trunks,contexts))
	file:close()
	file = io.open("/etc/asterisk/sip.conf","w")
	file:write(makeSipConf(sipDevices,providers))
	file:close()
	file = io.open("/etc/asterisk/iax.conf","w")
	file:write(makeIaxConf(iaxDevices,providers))
	file:close()
	file = io.open("/etc/asterisk/manager.conf","w")
	file:write(makeManager())
	file:close()
	file = io.open("/etc/asterisk/features.conf","w")
	file:write(makeFeatures())
	file:close()
	file = io.open("/etc/asterisk/http.conf","w")
	file:write(makeHttp())
	file:close()
	file = io.open("/etc/asterisk/musiconhold.conf","w")
	file:write(makeMusicOnHold())
	file:close()
end
print(makeSipConf(sipDevices,providers))
print(makeIaxConf(iaxDevices,providers))
print(makeExtensionsConf(dials,trunks,contexts))
print(makeManager())
print(makeFeatures())
print(makeHttp())
print(makeMusicOnHold())

--[[
for i, t in pairs(sipDevices) do
  print(i, t)
  for k, v in pairs(t) do
	print("",k,v)
  end
end
]]
--[[
for i, v in pairs(uci.get_all("asterisk")) do
	print(i,v)
end
]]
